﻿/* =====================================================================================================
* FileName: AsyncSocketServer            
* Created By: 马志
* Created Date: 2015年12月16日
* Email：hautmz@163.com
* Modified By:
* Modified Date:
* Copyright (c) 2010 - 2015 北京其乐融融科技有限公司
* ===================================================================================================== */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;
using PluginBase.Common;

namespace PluginBase.Sockets
{
    public delegate void SocketConnectedHandler<T>(AsyncSocketConnect<T> connect) where T:class ;
    public delegate void SocketCollectionChangeHandler<T>(AsyncSocketConnect<T> connect, CollectionChangeType changType) where T : class;
    public class AsyncSocketServer<T>  where T : class 
    {
        #region 变量

        protected Socket _socket = null;
        protected AsyncSocketConnects<T> _connects = new AsyncSocketConnects<T>();
        string _name = "undefine";
        protected int _port = 0;
        protected int _backLog = 0;
        protected Encoding _Encoding = UTF8Encoding.UTF8;
        //protected TransferMode _TransferMode = TransferMode.Stream;

        #endregion

        #region 属性

        public int ConnectCount
        {
            get
            {
                return _connects.Count;
            }
        }

        public AsyncSocketConnects<T> Connects
        {
            get { return _connects; }
        }

        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }

        public string Url {
            get {
                if (_socket!=null)
                {
                    return string.Format("{0}:{1}", _socket.LocalEndPoint.ToString(), _port);
                }
                return string.Empty;
            }
        }

       

        #endregion

        #region 事件

        public event SocketConnectedHandler<T> OnConnectedServer;
        public event SocketCollectionChangeHandler<T> OnSocketCollectionChange;
        public event HandleMessageHandler<T> OnReceivedMessage;
        public event ExceptionHandler OnError;

        #endregion

        #region 构造函数

        public AsyncSocketServer(int port, int backLog)
        {
            //_TransferMode = transferMode;
            _port = port;
            _backLog = backLog;
            //InitSocket();
        }

        //public AsyncSocketServer()
        //{
        //    Config.AsyncSocketServerConfig config =
        //        ConfigurationManager.GetSection("AsyncSocketServerConfig") as
        //        Config.AsyncSocketServerConfig;
        //    _TransferMode = config.TransferMode;
        //    _port = config.Port;
        //    _BackLog = config.MaxConnectCount;
        //    InitSocket();
        //}

        #endregion

        #region 公共函数

        public virtual void InitSocket()
        {
            _socket = new Socket(
                AddressFamily.InterNetwork,
                SocketType.Stream,
                ProtocolType.Tcp);
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, _port);
            _socket.Bind(endPoint);
        }

        public void Listen()
        {
            _socket.Listen(_backLog);
            _socket.BeginAccept(AcceptCallback, null);
        }

        public void Close()
        {
            _socket.Close();
            InitSocket();
        }

        #endregion

        #region 私有函数

        private void AcceptCallback(IAsyncResult iar)
        {
            try
            {
                /*
                 * error:ling 138 ,System.ObjectDisposedException: 无法访问已释放的对象。
                 * 对象名:“System.Net.Sockets.Socket”
                 */
                Socket socket = _socket.EndAccept(iar);
                AsyncSocketConnect<T> asyncConn = CreateClientConnect(socket);
                HandConnectedServer(asyncConn);
                if (asyncConn.Actived)
                {
                    asyncConn.OnSocketInvalided += new SocketInvalidedHandler<T>(asyncConn_OnSocketInvalided);
                    asyncConn.OnReceivedMessage += new HandleMessageHandler<T>(asyncConn_OnReceivedMessage);
                    asyncConn.OnError += new ExceptionHandler(asyncConn_OnError);
                    asyncConn.IRecieveArgs = CreateReciveArgsInstance();
                    //asyncConn.OnRequestHandle += new HandleRequestHandler(asyncConn_OnRequestHandle);
                    _connects.Add(asyncConn);

                    HandlerSocketCollectionChange(asyncConn, CollectionChangeType.Add);
                    asyncConn.BeginReciveData();
                    
                }
                _socket.BeginAccept(AcceptCallback, null);
                
            }
            catch(Exception e)
            {
                HandError(this,e);
            }
        }

        private void HandConnectedServer(AsyncSocketConnect<T> clientConnect)
        {
            if (OnConnectedServer != null)
            {
                OnConnectedServer(clientConnect);
            }
        }

        private void asyncConn_OnSocketInvalided(AsyncSocketConnect<T> connect, string errMsg)
        {
            if (_connects.Keys.Contains(connect.ID))
            {
                try
                {
                    _connects.Remove(connect.ID);
                    connect.OnSocketInvalided -= new SocketInvalidedHandler<T>(asyncConn_OnSocketInvalided);
                    connect.OnReceivedMessage -= new HandleMessageHandler<T>(asyncConn_OnReceivedMessage);
                    connect.OnError -= new ExceptionHandler(asyncConn_OnError);
                   
                    //connect.OnRequestHandle -= new HandleRequestHandler(asyncConn_OnRequestHandle);
                    HandlerSocketCollectionChange(connect, CollectionChangeType.Remove);
                    //if (OnSocketCollectionChange != null)
                    //    OnSocketCollectionChange(connect, CollectionChangeType.Remove);
                }
                catch (Exception e)
                {
                    HandError(this, e);
                }
            }
        }

        private void asyncConn_OnReceivedMessage(AsyncMessageHandleArgs<T> args)
        {
            if (OnReceivedMessage!=null)
            {
                OnReceivedMessage(args);
            }
        }

        private void asyncConn_OnError(object sender, Exception e)
        {
            HandError(sender, e);
        }

        private void HandlerSocketCollectionChange(AsyncSocketConnect<T> connect, CollectionChangeType changeType)
        {
            InnerSocketCollectionChangeHandler(connect, changeType);
            if (OnSocketCollectionChange != null)
                OnSocketCollectionChange(connect, changeType);
        }

        private void HandError(object sender,Exception e)
        {
            if (OnError!=null)
            {
                OnError(sender, e);
            }
        }

        #endregion

        #region 受保护虚函数

        protected virtual AsyncSocketConnect<T> CreateClientConnect(Socket socket)
        {
            return AsyncSocketConnect<T>.CreateAcceptSocket(socket);
        }

        protected virtual IRecieveArgs<T> CreateReciveArgsInstance()
        {
            return new AsyncReceiveArgs() as IRecieveArgs<T>;
        }

        protected virtual void InnerSocketCollectionChangeHandler(AsyncSocketConnect<T> connect, CollectionChangeType changeType)
        {

        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            _connects.EnterWriteLock();
            try
            {
                foreach (var conn in _connects.Values)
                    conn.Close();

                _connects.Clear();

                _socket.Close();
            }
            finally
            {
                _connects.ExitWriteLock();
            }
        }

        #endregion

    }
}